Looping


The NIH Image macro language has the standard set of pascal loops. This includes "for" loops and "while" loops. Although close to pascal, the macro language doesn't have everything as this email shows:

From wayne@helix.nih.gov (Wayne Rasband) reply on nih-image@soils.umn.edu

>in the "for" command (as in for i= 1 to fred Do) is there a skip command.
>For example, can I choose to do:
> for i = 1 to fred by 10 DO

The NIH Image macro language is (almost) a subset of Pascal and the Pascal FOR statement does not have a BY option. Instead, use a WHILE loop. For example:
    i:=1;
    while i<=fred do begin
       {process}
        i:=i+10;
    end;

Regions of Interest (ROI)

Before you start looking at macro ROI's an introduction to coordinates is worthwhile. See the picture below for a general guideline. Regions of interest are characterized by 'marching ants' which surround a selection.


Getting ROI information

GetRoi(left,top,width,height)
You will want to call this macro routine if you need any information about the current ROI. The routine returns a width of zero if no ROI exists.

ROI creation

SelectAll
The Selectall macro command is equivalent to the Pascal SelectAll(true), which selects all of the image and shows the ROI's 'marching ants'. See the above paragraph for pascal code relating to Selectall.

MakeRoi(left,top,width,height)
This is as straight forward as the name implies.
MakeOvalRoi(left,top,width,height)
Not terribly differing to implement from MakeROI. If you want a circular ROI set width and height to the same value. See the example below.

Altering an existing ROI

MoveRoi(dx,dy)
Use to move right dx and down dy.

InsetRoi(delta)
Expands the ROI if delta is negative, Shrinks the ROI if delta is positive.

Other routines involving ROI's

RestoreROI,KillRoi
These are opposities.

Copy,Paste,Clear,Fill,Invert,DrawBoundary

Detecting the press of the mouse button

The example below shows a macro which operates until the mouse button is pressed. Button is your basic true or false boolean and becomes true when the button is pressed.

macro 'Show RGB Values [S]';
var
  x,y,v,savex,savey:integer;
begin
  repeat
    savex:=x; savey:=y;
    GetMouse(x,y);
    if (x<>savex) or (y<>savey) then begin
      v:=GetPixel(x,y);
      ShowMessage('loc=',x:1,', ',y:1,
        '\value=',v:1,
        '\RGB=',RedLUT[v]:1,', ',GreenLUT[v]:1,', ',BlueLUT[v]:1);
      wait(.5);
    end;
until button;
end;

Detecting press of option, shift and control keys

The macro "KeyDown(key)" (Key = 'option', 'shift', or 'control') returns a boolean true or false. It returns TRUE if the specified key is down. The example macro below can be run on any stack, using shift to delay more or control to delay less.


macro 'Animate Stack';
var
  i,delay:integer;
begin
  RequiresVersion(1.56);
  i:=0;
  delay:=0.1;
  repeat
    i:=i+1;
    if i>nSlices then i:=1;
    Wait(delay);
    SelectSlice(i);
    if 
KeyDown('shift')
 then delay:=1.5*delay;
    if delay>1 then delay:=1;
    if 
KeyDown('control')
 then delay:=0.66*delay;
    if 
KeyDown('option')
 then beep;
    ShowMessage('delay=',delay:4:2);
  until button;
end;

Measurement and rUser Arrays

There are a number of arrays in macros, but there are two varieties the measurement arrays and the rUser arrays. You can store macro data and results in the rUser arrays. These arrays are not affected by the Measurement counter (rCount) which works with measurements arrays such as rMean[rCount], rArea, etc. The current rCount for these is changed by doing a measurement or calling SetCounter.

Example of storing data to the rUser arrays:

  rUser1[1]:=SomeNumber;
  rUser2[1]:=SomeOtherNumber;

If you have more than two sets of data which you'd like to keep, and because there are only two rUser arrays, then you can access other macro arrays. This includes rArea, rMean, rStdDev, rX, rY, rMin, rMax, rLength, rMajor, rMinor, and rAngle. However you will need to be careful because these arrays are affected by the rCount value and you could write over your data. An example use of measurement arrays outside the intended use is a snipet of code from the Export look up table macro:
for i:=0 to 255 do begin
    rArea[i+1]:=RedLut[i];
    rMean[i+1]:=GreenLut[i];
    rLength[i+1]:=BlueLut[i];
  end;
Here rArea, rMean and rLength are used for Red, Green and Blue instead of area, mean and length.

Placing macro data in the "Results" window

If you have particular information, data, calculated results, or any type of numeric data which you want to keep, you can redirect it into the Results window. Use the SetUser label commands to title your field name. The rCount function keeps the current index of the measurement counter. Since rUser1 and rUser2 are arrays, you specify the index of the array with the rCount value. See below.

macro 'Count Black and White Pixels [B]';
{
Counts the number of black and white pixels in the current
selection and stores the counts in the User1 and User2 columns.
}
begin
  RequiresVersion(1.44);
  SetUser1Label('Black');
  SetUser2Label('White');
  Measure;
  rUser1[rCount]:=histogram[255];
  rUser2[rCount]:=histogram[0];
  UpdateResults;
end;



Saving results data to a tab delimeted file


You can also save data from the macro, to a tab delimeted text file by adding several commands in your macro:

  SetExport('Measurements');
  Export('YourFileName');

Operating on each image in a stack (SelectSlice)

By using a loop (for i:= 1 to nSlices) you can operate on a series of 2D images. The nSlices function returns the number of slices in the stack.

macro 'Reduce Noise';
var
  i:integer;
begin
    if nSlices=0 then begin
    PutMessage('This window is not a stack');
    exit;
  end;
  for i:= 1 to nSlices do begin
    SelectSlice(i);
    ReduceNoise;   {Call any routine you want, including UserCode}
  end;
end;
See the series of stack macros distributed with the Image program for more examples.


Extracting a substring from a string

From reply of Doug Morris <dmorris@bmrl.med.uiuc.edu> on nih-image@soils.umn.edu

> I have a question about how to "extract" a substring from a string using > NIH Image macro language. It doesn't seem to have pascal's "copy(source, > index, count)" function implemented at macro language level. It is possible to work around this particular problem. Below is an example macro that will allow you to pull a substring out of a string.Just cut it out of the mail message and read into image.
{
     An example routine to return a substring from a string in NIH Image macro.
}
var
      ReturnString:string;

procedure copystring(SourceString:string,index:integer,count:integer);
begin;
       ReturnString:=SourceString;
       if index > 0 then Delete(ReturnString,0,index);
       Delete(ReturnString,count+1,length(ReturnString)-count);
end;

macro 'test copystring'
   var 
      TestString:string;
begin
     TestString:='This is a test';
     copystring(TestString,11,4);
     PutMessage('The Returned String is :  ' ReturnString);
end;